﻿using MCP.BL;
using MCP.BL.Messages;
using MCP.Model.Helpers;
using MCP.Model.Repositories.Interfaces;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using client = MCP.Data.Client;
using server = MCP.Data.CF_Entities;

namespace MCP.Model.Repositories.CF
{
	public class CheckRepository : ICheckRepository
	{
		private readonly MCPContext context;
		private readonly IUnitOfWork unitOfWork;

		public CheckRepository(IUnitOfWork unitOfWork, MCPContext context)
		{
			this.context = context;
			this.unitOfWork = unitOfWork;
		}

		//public IQueryable<Check> GetChecks(Guid userID)
		//{
		//    if (userID == null || userID == Guid.Empty) return null;

		//    return this.context.Checks.Where(c => c.UserID == userID);
		//}

		public OperationResult<IEnumerable<client.Check>> GetChecks()
		{
			OperationResult<IEnumerable<client.Check>> result;

			try
			{
				var checks = this.context.Checks
					.Include("Items.Categories")
					.Where(c => c.UserID == CurrentUserHelper.UserID)
					.ToList();

				if (checks.Any())
				{
					checks = checks.OrderByDescending(c => c.Date).ToList();
				}

				result = new OperationResult<IEnumerable<client.Check>>((IEnumerable<client.Check>)checks.ToClientChecks());
			}
			catch (Exception exc)
			{
				result = new OperationResult<IEnumerable<client.Check>>(exc);
			}
			return result;
		}

		//public List<Check> GetThisMonthCheck(Guid userID)
		//{
		//	if (userID == null || userID == Guid.Empty) return null;

		//	return this.context.Checks.Where(c => c.UserID == userID && c.Date.Month == DateTime.Now.Month).ToList();
		//}

		public OperationResult AddNewCheck(client.Check checkToAdd)
		{
			OperationResult result;

			try
			{
				var userID =
					CurrentUserHelper.UserID;
					//new Guid("36D6D667-E854-4D54-8F7A-C81AC46CC7E3");
				server.Check serverCheckToAdd = new server.Check()
					{
						TotalPrice = checkToAdd.TotalPrice,
						Date = DateTime.Now,
						UserID = userID,
						Items = new Collection<server.Item>()
					};

				// add items to server check:
				foreach (var item in checkToAdd.Items)
				{
					var serverItem = new server.Item()
					{
						CheckID = serverCheckToAdd.ID,
						Amount = item.Amount,
						Name = item.Name,
						Price = item.Price,
						Categories = new Collection<server.Category>()
					};

					var categoriesDB = this.context.Categories.ToList();

					// add categories:
					if (item.Categories != null && item.Categories.Any())
					{
						if (!categoriesDB.Any())
						{
							item.Categories.ForEach(c => serverItem.Categories.Add(new server.Category { CategoryName = c }));
						}
						else
						{
							foreach (var categoryName in item.Categories)
							{
								var serverCategory = categoriesDB.Single(c => c.CategoryName == categoryName); // not null if existed in db
								serverItem.Categories.Add(serverCategory ?? new server.Category { CategoryName = categoryName });
							}
						}
					}

					// add server item to server check:
					serverCheckToAdd.Items.Add(serverItem);
				}

				this.context.Checks.Add(serverCheckToAdd);

				this.context.SaveChanges();

				result = new OperationResult(true
					//, SimpleMessage.Check.GetCheckCreatedSuccessfulyMessage()
					);
			}
			catch (Exception exc)
			{
				result = new OperationResult(exc);
			}


			return result;
		}

		public OperationResult<client.Check> GetCheckDetails(int checkID)
		{
			OperationResult<client.Check> result;
			try
			{
				result = new OperationResult<client.Check>(this.context.Checks.SingleOrDefault(c => c.ID == checkID).ToClientCheck());
			}
			catch (Exception exc)
			{
				result = new OperationResult<client.Check>(exc);
			}

			return result;
		}

		public OperationResult DeleteCheck(int checkID)
		{
			OperationResult result;

			try
			{
				if (!this.context.Checks.Any(c => c.ID == checkID))
				{
					result = new OperationResult(false, new ErrorMessage(new ArgumentNullException("checkID", "No check with such ID have been found.")));
				}
				else
				{
					var checkToDelete = this.context.Checks.SingleOrDefault(c => c.ID == checkID);
					this.context.Checks.Remove(checkToDelete);
					this.context.SaveChanges();

					result = new OperationResult(true
						//, SimpleMessage.Check.GetCheckDeletedMessage(checkToDelete)
						);
				}
			}
			catch (Exception exc)
			{
				result = new OperationResult(exc);
			}

			return result;
		}

		#region IDisposable
		// Copied from:
		// http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

		private bool disposed = false;

		protected virtual void Dispose(bool disposing)
		{
			if (!this.disposed)
			{
				if (disposing)
				{
					context.Dispose();
				}
			}
			this.disposed = true;
		}

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		#endregion
	}
}
